package com.m.sms.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.m.sms.annotation.SmsLimit;
import com.m.sms.response.SmsSendResponseBody;
import com.m.sms.response.SmsSendStatus;
import com.m.sms.enums.SmsStatusEnum;
import com.m.sms.exception.ValidateParamsException;
import com.m.sms.params.SmsSendRequestBody;
import com.m.sms.properties.YunpianProperties;
import com.m.sms.service.ISmsService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Description
 *
 * @Auther [li.wang@jsxfedu.com]
 * @Date 2025/3/20 13:18
 * @Version 1.0
 * @Copyright (c) 2022 京师讯飞
 */
@Slf4j
@AllArgsConstructor
public class YunpianSmsServiceImpl implements ISmsService {

    /**
     * 模板发送接口的http地址
     */
    private final static String URI_TPL_SEND_SMS = "https://sms.yunpian.com/v2/sms/tpl_single_send.json";
    /**
     * 批量模板发送接口的http地址
     */
    private final static String URI_TPL_BATCH_SEND_SMS = "https://sms.yunpian.com/v2/sms/tpl_batch_send.json";
    /**
     * 编码格式。发送编码格式统一用UTF-8
     */
    private final static String ENCODING = "UTF-8";
    /**
     * 模板参数的替换规则
     */
    private final static String TPL_VALUE_KEY = "#%s#=%s";

    /**
     * 云片官方限制批量最大支持1000
     */
    private final static int MAX_MOBILE_LENGTH = 1000;

    private YunpianProperties yunpianProperties;

    @SmsLimit(value ="#smsSendRequestBody.mobile")
    @Override
    public SmsSendResponseBody sendSms(SmsSendRequestBody smsSendRequestBody) {
        validateParams(smsSendRequestBody);

        Map<String, String> params = new HashMap<>();
        params.put("apikey", yunpianProperties.getApikey());
        params.put("tpl_id", smsSendRequestBody.getTelId());
        params.put("tpl_value", smsSendRequestBody.getMobile());

        if (CollectionUtil.isNotEmpty(smsSendRequestBody.getTelParam())) {
            StringBuffer tplParams = new StringBuffer();
            smsSendRequestBody.getTelParam().forEach((k, v) -> {
                try {
                    tplParams.append(String.format(TPL_VALUE_KEY, URLEncoder.encode(k, ENCODING), URLEncoder.encode(v, ENCODING)));
                } catch (UnsupportedEncodingException e) {
                    log.error("云片短信封装参数异常：{} \r\n{}", e.getMessage(), e);
                    throw new RuntimeException(e);
                }
                tplParams.append("&");
            });
            params.put("tpl_value", tplParams.toString().substring(0, tplParams.toString().length() - 1));
        }

        String url;
        boolean isBatch = Boolean.FALSE;
        if (CollectionUtil.isNotEmpty(smsSendRequestBody.getMobileList())) {
            if (smsSendRequestBody.getMobileList().size() > MAX_MOBILE_LENGTH) {
                throw new ValidateParamsException(String.format("单次批量发送短信不能超过%s条", MAX_MOBILE_LENGTH));
            }
            isBatch = Boolean.TRUE;
            params.put("mobile", smsSendRequestBody.getMobileList().stream().collect(Collectors.joining(",")));
            url = URI_TPL_BATCH_SEND_SMS;
        } else {
            params.put("mobile", smsSendRequestBody.getMobile());
            url = URI_TPL_SEND_SMS;
        }
        String response = post(url, params);
        log.info("云片发送短信结果：{}", response);
        JSONObject responseJson = JSONObject.parseObject(response);
        SmsSendResponseBody smsSendResponseBody = new SmsSendResponseBody();
        if(isBatch){
            for (Object data : responseJson.getJSONArray("data")) {
                smsSendResponseBody.getSendStatusList().add(wrapperResult((JSONObject) data));
            }
        }else{
            smsSendResponseBody.getSendStatusList().add(wrapperResult(responseJson));
        }
        smsSendResponseBody.setTotalCount(smsSendResponseBody.getSendStatusList().size());
        smsSendResponseBody.setFailCount((int) smsSendResponseBody.getSendStatusList().stream().filter(o -> !SmsStatusEnum.SUCCESS.equals(o.getStatus())).count());
        return smsSendResponseBody;
    }

    /**
     * 封装结果
     * @param responseJson
     */
    private SmsSendStatus wrapperResult(JSONObject responseJson) {
        SmsSendStatus smsSendStatus = new SmsSendStatus();
        if (responseJson.containsKey("http_status_code")) {
            int httpStatusCode = responseJson.getInteger("http_status_code");
            if (httpStatusCode == 400) {
                smsSendStatus.setStatus(SmsStatusEnum.PARAMETER_FAIL);
            } else {
                smsSendStatus.setStatus(SmsStatusEnum.FAIL);
            }
        } else {
            smsSendStatus.setStatus(SmsStatusEnum.SUCCESS);
        }
        smsSendStatus.setMsg(responseJson.getString("msg"));
        smsSendStatus.setDetail(responseJson.getString("detail"));
        smsSendStatus.setMobile(responseJson.getString("mobile"));
        return smsSendStatus;
    }


    /**
     * 基于HttpClient 4.3的通用POST方法
     *
     * @param url       提交的URL
     * @param paramsMap 提交<参数，值>Map
     * @return 提交响应
     */
    private String post(String url, Map<String, String> paramsMap) {
        CloseableHttpClient client = HttpClients.createDefault();
        String responseText = "";
        CloseableHttpResponse response = null;
        try {
            HttpPost method = new HttpPost(url);
            if (paramsMap != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (Map.Entry<String, String> param : paramsMap.entrySet()) {
                    NameValuePair pair = new BasicNameValuePair(param.getKey(),
                            param.getValue());
                    paramList.add(pair);
                }
                method.setEntity(new UrlEncodedFormEntity(paramList, ENCODING));
            }
            response = client.execute(method);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                responseText = EntityUtils.toString(entity, ENCODING);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return responseText;
    }

}
